package nf.translat.model;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;

//反射类   https://zhuanlan.zhihu.com/p/80519709
public class Reflection {
    Class C;
    Object Obj;
    HashMap <String,Method> methods=new HashMap<String, Method>();
    public Reflection(Object obj){
        C=obj.getClass();
        Obj=obj;
    }

    public HashMap <String,Method> getMethods(){
        HashMap<String,Method> rt=new HashMap<String,Method>();
        //Method[] methods=C.getDeclaredMethods();
        Method[] methods=C.getMethods();
        for(int i=0;i<methods.length;i++) {
            Method method = methods[i];
            String mname = method.getName();
            rt.put(mname,method);
        }
        return rt;
    }

    public boolean method_exists(String name) {
        if(methods.isEmpty()) methods=getMethods();
        return methods.get(name)!=null ? true: false;
    }

    public String[] getFields(){
        Field[] attrs=C.getDeclaredFields();
        ArrayList<String> list=new ArrayList<String>();
        for(int i=0;i<attrs.length;i++) {
            Field field = attrs[i];
            if(Modifier.isStatic(field.getModifiers())) continue;
            String key = field.getName();
            list.add(key);
        }
        String[] rt=new String[list.size()];
        list.toArray(rt);
        return rt;
    }

    public var method_call(var name, Object... args){
        return method_call(name.toString(),args);
    }
    
    public var method_call(String name, Object... args){
        try {
            Class[] params=args.length>0 ? new Class[args.length]: null;
            for(int i=0;i<args.length;i++) params[i]=args[i].getClass();
            Method mt =  C.getMethod(name,params);
//            if (mt.getParameterCount() == args.length) 
            mt.setAccessible(true);
            return var.valueOf(mt.invoke(Obj,args));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return var.valueOf(false);
    }

    public var getField(String key) {
        Field field= null;
        try {
            field = C.getField(key);
            return var.valueOf(field.get(Obj));
        } catch (Exception e) {
            e.printStackTrace();
        }

        String mname="get" + key.substring(0, 1).toUpperCase() + key.substring(1);
        if(method_exists(mname)) {
            return method_call(mname);
        }

        return new var();
    }

    public boolean setField(String k, var v) {
        try {
            Field attr = C.getDeclaredField(k);
            String mname="set" + k.substring(0, 1).toUpperCase() + k.substring(1);
            Object t =attr.getType();

            if(Modifier.isPublic(attr.getModifiers())) {
                attr.set(Obj,v.to(t));
            }else if(method_exists(mname)){
                method_call(mname,v.to(t));
            }
            return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}
